#include "tcp_widget.h"

TcpWidget::TcpWidget(QWidget *parent) : QWidget(parent) {
    initUI();
    loadStyleSheet();
    initModel();

    tcpServer = new QTcpServer(this);
    tcpSocket = new QTcpSocket(this);

    initBindingSignalSlot();
}

void TcpWidget::initUI() {
    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    textEdit = new QTextEdit();
    QWidget *operWidget = new QWidget();
    mainLayout->addWidget(textEdit, 4);
    mainLayout->addWidget(operWidget, 2);

    QVBoxLayout *operLayout = new QVBoxLayout();
    operWidget->setLayout(operLayout);
    // ip 端口
    QHBoxLayout *ipPortLayout = new QHBoxLayout();
    operLayout->addLayout(ipPortLayout);
    QLabel *protocolLabel = new QLabel("服务类型");
    protocolComboBox = new QComboBox();
    protocolComboBox->setMinimumWidth(120);
    QLabel *localIPLabl = new QLabel("本地IP");
    localIPComboBox = new QComboBox();
    localIPComboBox->setMinimumWidth(150);
    QLabel *serverIpLabel = new QLabel("服务器IP");
    serverIPLineEdit = new QLineEdit();
    serverIPLineEdit->setMinimumWidth(150);
    serverIPLineEdit->setEnabled(false);
    QLabel *listenPortLabel = new QLabel("监听端口");
    listenPortLineEdit = new QLineEdit();
    listenPortLineEdit->setMinimumWidth(150);
    ipPortLayout->addWidget(protocolLabel);
    ipPortLayout->addWidget(protocolComboBox);
    ipPortLayout->addSpacing(30);
    ipPortLayout->addWidget(localIPLabl);
    ipPortLayout->addWidget(localIPComboBox);
    ipPortLayout->addSpacing(30);
    ipPortLayout->addWidget(serverIpLabel);
    ipPortLayout->addWidget(serverIPLineEdit);
    ipPortLayout->addSpacing(30);
    ipPortLayout->addWidget(listenPortLabel);
    ipPortLayout->addWidget(listenPortLineEdit);
    ipPortLayout->addStretch();

    // 控制行
    QHBoxLayout *controlLayout = new QHBoxLayout();
    operLayout->addLayout(controlLayout);
    hexShowCheckBox = new QCheckBox("十六进制显示");
    autoLineCheckBox = new QCheckBox("自动换行");
    autoLineCheckBox->setChecked(true);
    hexSendCheckBox = new QCheckBox("十六进制发送");
    showTimeCheckBox = new QCheckBox("显示时间");
    showTimeCheckBox->setChecked(true);
    clearButton = new QPushButton("清空");
    startOrStopButton = new QPushButton("开始监听");
    controlLayout->addWidget(hexShowCheckBox);
    controlLayout->addSpacing(30);
    controlLayout->addWidget(autoLineCheckBox);
    controlLayout->addSpacing(30);
    controlLayout->addWidget(hexSendCheckBox);
    controlLayout->addSpacing(30);
    controlLayout->addWidget(showTimeCheckBox);
    controlLayout->addStretch();
    controlLayout->addWidget(clearButton);
    controlLayout->addSpacing(30);
    controlLayout->addWidget(startOrStopButton);
    controlLayout->addSpacing(30);

    // 发送
    QHBoxLayout *sendLayout = new QHBoxLayout();
    operLayout->addLayout(sendLayout);
    sendTextEdit = new QTextEdit();
    sendTextEdit->setFixedHeight(80);
    sendTextEdit->setPlaceholderText("请输入发送内容");
    sendButton = new QPushButton("发送");
    sendLayout->addWidget(sendTextEdit);
    sendLayout->addWidget(sendButton);
    sendLayout->addSpacing(30);

    // 底部状态
    QHBoxLayout *bottomLayout = new QHBoxLayout();
    mainLayout->addLayout(bottomLayout);
    statusLabel = new QLabel();
    sendLabel = new QLabel();
    recvLabel = new QLabel();
    bottomLayout->addWidget(statusLabel);
    bottomLayout->addWidget(sendLabel);
    bottomLayout->addWidget(recvLabel);
}

void TcpWidget::loadStyleSheet() {
    QFile file(":/resources/style/tcp_widget.qss");
    if (file.open(QFile::ReadOnly)) {
        QString styleSheet = this->styleSheet();
        styleSheet += file.readAll();
        this->setStyleSheet(styleSheet);
    }
}

void TcpWidget::initModel() {
    QStringList protocol = {"服务器", "客户端"};
    protocolComboBox->addItems(protocol);

    getLocalHostIP();
}

void TcpWidget::getLocalHostIP() {
    // 获取所有的网络接口
    QList<QNetworkInterface> listInterface = QNetworkInterface::allInterfaces();
    for (QNetworkInterface interface : listInterface) {
        // 获取IP地址 子网掩码 广播地址
        QList<QNetworkAddressEntry> entryList = interface.addressEntries();
        for (QNetworkAddressEntry entry : entryList) {
            // 过滤ip6
            if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                localIPComboBox->addItem(entry.ip().toString());
                ipList << entry.ip();
            }
        }
    }
}

void TcpWidget::initBindingSignalSlot() {
    connect(protocolComboBox, &QComboBox::currentTextChanged, this, &TcpWidget::on_protocolComboBox_textChanged);
    connect(clearButton, &QPushButton::clicked, this, &TcpWidget::on_clearButton_clicked);
    connect(startOrStopButton, &QPushButton::clicked, this, &TcpWidget::on_startOrStopButton_clicked);
    connect(tcpServer, &QTcpServer::newConnection, this, &TcpWidget::clientConnected);
    connect(sendButton, &QPushButton::clicked, this, &TcpWidget::sendMessage);
    connect(tcpSocket, &QTcpSocket::readyRead, this, &TcpWidget::receiveMessage);
    connect(tcpSocket, &QTcpSocket::stateChanged, this, &TcpWidget::socketStateChange);
}

void TcpWidget::on_protocolComboBox_textChanged(const QString &text) {
    if (text == "服务器") {
        serverIPLineEdit->setEnabled(false);
    } else {
        serverIPLineEdit->setEnabled(true);
    }
}

void TcpWidget::on_clearButton_clicked() { textEdit->clear(); }

// 开始/关闭监听
void TcpWidget::on_startOrStopButton_clicked() {
    if (protocolComboBox->currentText() == "服务器") {
        if (!isStartListen) {
            startListen();
            isStartListen = true;
            qDebug() << "服务器开启监听";
        } else {
            stopListen();
            isStartListen = false;
            qDebug() << "服务器停止监听";
        }
    } else { // 客户端
        if (!isStartListen) {
            toConnect();
            isStartListen = true;
        } else {
            toDisconnect();
            isStartListen = false;
        }
    }
}

void TcpWidget::startListen() {
    // 判断是否选中本地ip
    if (localIPComboBox->currentIndex() != -1) {
        if (listenPortLineEdit->text() != "" && listenPortLineEdit->text().toInt() >= 0 &&
            listenPortLineEdit->text().toInt() <= 65535) {
            tcpServer->listen(ipList[localIPComboBox->currentIndex()], listenPortLineEdit->text().toInt());
            // 设置控件状态
            protocolComboBox->setEnabled(false);
            localIPComboBox->setEnabled(false);
            listenPortLineEdit->setEnabled(false);
            startOrStopButton->setText("停止监听");

            textEdit->append("服务器IP地址:" + localIPComboBox->currentText());
            textEdit->append("监听端口:" + listenPortLineEdit->text());
        } else {
            statusLabel->setText("请输入正确的端口号");
        }
    } else {
        statusLabel->setText("请选择本地IP");
    }
}

void TcpWidget::stopListen() {
    startOrStopButton->setText("开始监听");
    protocolComboBox->setEnabled(true);
    localIPComboBox->setEnabled(true);
    listenPortLineEdit->setEnabled(true);

    // 断开客户端
    if (clientSocket->state() == QAbstractSocket::ConnectedState) {
        clientSocket->disconnectFromHost(); // 断开客户端
    }
    tcpServer->close();
}

// 客户端连接
void TcpWidget::clientConnected() {
    clientSocket = tcpServer->nextPendingConnection();
    QString ip = clientSocket->peerAddress().toString();
    quint16 port = clientSocket->peerPort();
    textEdit->append("客户端连接成功");
    textEdit->append("客户端IP地址:" + ip);
    textEdit->append("客户端端口号:" + QString::number(port));
    connect(clientSocket, &QTcpSocket::readyRead, this, &TcpWidget::receiveMessage);
    connect(clientSocket, &QTcpSocket::stateChanged, this, &TcpWidget::socketStateChange);
}

void TcpWidget::receiveMessage() {
    QTcpSocket *socket;
    if (protocolComboBox->currentText() == "服务器") {
        socket = clientSocket;
    } else {
        socket = tcpSocket;
    }
    QByteArray data = socket->readAll();
    QString receiveTime = "";
    // 接收时间显示
    if (showTimeCheckBox->isChecked()) {
        receiveTime += "[" + getDateTimeToFormat() + "]  ";
    }
    receiveTime += "接收:  ";
    if (hexShowCheckBox->isChecked()) {
        // 16 进制格式显示
        QString hexStr;
        for (char byte : data) {
            hexStr += QString("%1 ").arg((quint8)byte, 2, 16, QLatin1Char('0')).toUpper();
        }
        textEdit->insertPlainText(receiveTime + hexStr.trimmed());
    } else {
        // 文本形式显示 非可打印字符显示
        textEdit->insertPlainText(receiveTime + data);
    }
    if (autoLineCheckBox->isChecked()) {
        textEdit->append("");
    }
    readCount += data.size();
    recvLabel->setText(tr("接收:") + QString::number(readCount));
    textEdit->moveCursor(QTextCursor::End);
    textEdit->ensureCursorVisible();
}

void TcpWidget::sendMessage() {
    if (clientSocket == NULL) {
        return;
    }
    QTcpSocket *socket;
    if (protocolComboBox->currentText() == "服务器") {
        socket = clientSocket;
    } else {
        socket = tcpSocket;
    }
    // 已经连接，发送消息
    if (socket->state() == socket->ConnectedState) {
        QString text = sendTextEdit->toPlainText();
        int write_size = 0;
        QByteArray data;

        // 检查是否是16进制数据
        if (hexSendCheckBox->isChecked()) {
            // 处理16进制数据 如 AA BB 0D
            QStringList list = text.split(' ', Qt::SkipEmptyParts);
            foreach (QString hex, list) {
                bool ok;
                char byte = hex.toInt(&ok, 16);
                if (ok && hex.length() == 2) {
                    data.append(byte);
                } else {
                    statusLabel->setText(tr("发送失败, 请检查数据是否是16进制数据"));
                    return;
                }
            }
        } else {
            data = text.toUtf8();
        }

        // 发送数据
        write_size = socket->write(data);
        if (write_size == -1) {
            statusLabel->setText(tr("发送失败"));
        } else {
            writeConunt += write_size;
            statusLabel->setText(tr("发送成功"));
            QString sendText = QString("发送:" + QString::number(writeConunt));
            sendLabel->setText(sendText);

            QString receiveTime = "";
            // 接收时间显示
            if (showTimeCheckBox->isChecked()) {
                receiveTime += "[" + getDateTimeToFormat() + "]  ";
            }
            receiveTime += "发送： ";
            textEdit->append(receiveTime + text);
            textEdit->moveCursor(QTextCursor::End);
            textEdit->ensureCursorVisible();
        }
    }
}

void TcpWidget::toConnect() {
    if (tcpSocket->state() != tcpSocket->ConnectedState) {
        if (serverIPLineEdit->text() != "") {
            if (listenPortLineEdit->text() != "" && listenPortLineEdit->text().toInt() >= 0 &&
                listenPortLineEdit->text().toInt() <= 65535) {
                tcpSocket->connectToHost(serverIPLineEdit->text(), listenPortLineEdit->text().toInt());
                // 设置控件状态
                protocolComboBox->setEnabled(false);
                localIPComboBox->setEnabled(false);
                listenPortLineEdit->setEnabled(false);
                startOrStopButton->setText("停止监听");

                textEdit->append("服务器IP地址:" + serverIPLineEdit->text());
                textEdit->append("监听端口:" + listenPortLineEdit->text());
            } else {
                statusLabel->setText("请输入正确的端口号");
            }
        } else {
            statusLabel->setText("请选择本地IP");
        }
    }
}

void TcpWidget::toDisconnect() {
    startOrStopButton->setText("开始监听");
    protocolComboBox->setEnabled(true);
    localIPComboBox->setEnabled(true);
    listenPortLineEdit->setEnabled(true);

    if (tcpSocket->state() == QAbstractSocket::ConnectedState) {
        tcpSocket->disconnectFromHost();
    }
    tcpSocket->close();
}

void TcpWidget::socketStateChange(QAbstractSocket::SocketState state) {
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        statusLabel->setText("socket状态: UnconnectedState");
        break;
    case QAbstractSocket::ConnectedState:
        statusLabel->setText("socket状态: ConnectedState");
        break;
    case QAbstractSocket::ConnectingState:
        statusLabel->setText("socket状态: ConnectingState");
        break;
    case QAbstractSocket::HostLookupState:
        statusLabel->setText("socket状态: HostLookupState");
        break;
    case QAbstractSocket::ClosingState:
        statusLabel->setText("socket状态: ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        statusLabel->setText("socket状态: ListeningState");
        break;
    case QAbstractSocket::BoundState:
        statusLabel->setText("socket状态: BoundState");
        break;
    default:
        break;
    }
}